package org.game.manager;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.cfg.EndlessCloisterLevelCfg;
import org.cfg.cache.DiscreteDataCfgCache;
import org.cfg.cache.EndlessCloisterLevelCfgCache;
import org.constant.DiscreteDataID;
import org.constant.DiscreteDataKey;
import org.constant.MailConstant;
import org.game.cache.OnlinePlayerCache;
import org.game.constant.EndlessCloisterConstant;
import org.game.db.bean.Player;
import org.game.db.proxy.bean.PlayerDataProxy;
import org.game.db.vo.PlayerDataVO.EndlessVO;
import org.game.log.builder.LogDsp;
import org.game.log.dsp.GoodsDsp;
import org.game.module.endlesscloisterbo.EndlessCloisterBO;
import org.game.msgBuilder.EndlessCloisterMsgBuilder;
import org.game.protobuf.s2c.S2CEndlessCloisterMsg.RspEndlessCloisterInfo;
import org.game.util.ProtoUnit;
import com.alibaba.fastjson.JSONArray;
import com.sojoys.artifact.manager.MessageManager;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;


/**
 * 无尽回廊管理器
 * 
 * @author liu.jiang
 * @date 2018年3月13日
 */
public class EndlessCloisterManager {


    static final Log log = LogFactory.get(EndlessCloisterManager.class);

    /** 活动阶段 */
    private int step;
    /** 活动开启时间 */
    private long openTime;
    /** 活动结算时间 */
    private long balanceTime;
    /** 发放奖励及重置时间 */
    private long resetTime;
    /** 跳级封装对象集合 */
    private List<SkipLevelsObj> skipList;
    /** 对应每周各天的挑战关卡ID集合 */
    private Map<Integer, List<Integer>> weekLevelMap;
    /** 临时计时时间 */
    private Date date = new Date();

    private static EndlessCloisterManager ME = new EndlessCloisterManager();

    private EndlessCloisterManager() {}

    public static EndlessCloisterManager me() {
        return ME;
    }

    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }

    public int getClientStep() {
        // 对于客户端来说，结束阶段也是准备阶段
        return step == EndlessCloisterConstant.STEP_OVER ? EndlessCloisterConstant.STEP_READY
                : step;
    }

    /** 获取 进入下一阶段的时间(秒) */
    public int getNextStepTime() {
        long time = 0;
        if (step == EndlessCloisterConstant.STEP_READY) {// 准备阶段
            time = openTime;
        } else if (step == EndlessCloisterConstant.STEP_OPEN) {// 开启阶段
            time = balanceTime;
        } else if (step == EndlessCloisterConstant.STEP_BALANCE) {// 结算阶段
            time = resetTime;
        } else if (step == EndlessCloisterConstant.STEP_OVER) {// 结束阶段
            // 还没有跨天，时间还未重置，则下一阶段开始时间要+1天，因为功能是在跨天时才重置时间
            time = openTime + DateUtils.MILLIS_PER_DAY;
        }
        return (int) (time / 1000);
    }

    public List<SkipLevelsObj> getSkipList() {
        return skipList;
    }

    public void setSkipList(List<SkipLevelsObj> skipList) {
        this.skipList = skipList;
    }

    /** 初始化 */
    public void init() {
        parseSkipLevels();
        parseWeekLevelMap();
        parseTimes();
    }

    /** 跳级封装对象集合 */
    private void parseSkipLevels() {
        JSONArray array =
                (JSONArray) DiscreteDataCfgCache.me().getData(DiscreteDataID.ENDLESS_CLOISTER,
                        DiscreteDataKey.SKIP_LEVELS);
        List<SkipLevelsObj> list = new ArrayList<SkipLevelsObj>();
        for (int i = 0; i < array.size(); i++) {
            String str = array.getString(i);
            String[] skip = StringUtils.split(str, ":");
            int skipLev = Integer.parseInt(skip[1]);
            String[] time = StringUtils.split(skip[0], "-");
            int minTime = Integer.parseInt(time[0]);
            int maxTime = Integer.parseInt(time[1]);
            SkipLevelsObj obj = new SkipLevelsObj(minTime, maxTime, skipLev);
            list.add(obj);
        }
        this.skipList = list;
    }

    /** 解析每周各天的挑战关卡ID集合 */
    private void parseWeekLevelMap() {
        weekLevelMap = new HashMap<Integer, List<Integer>>();
        List<EndlessCloisterLevelCfg> list = EndlessCloisterLevelCfgCache.me().getAll();
        for (EndlessCloisterLevelCfg cfg : list) {
            if (cfg.getId() <= 0) {
                continue;
            }
            List<Integer> ll = weekLevelMap.get(cfg.getWeek());
            if (ll == null) {
                ll = new ArrayList<Integer>();
                weekLevelMap.put(cfg.getWeek(), ll);
            }
            ll.add(cfg.getId());
        }
    }

    /** 解析各个时间 */
    private void parseTimes() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        // 活动开启时间
        String[] openTimeStr =
                StringUtils.split(
                        DiscreteDataCfgCache.me().getStringData(DiscreteDataID.ENDLESS_CLOISTER,
                                DiscreteDataKey.OPEN_TIME), ":");
        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(openTimeStr[0]));
        cal.set(Calendar.MINUTE, Integer.parseInt(openTimeStr[1]));
        openTime = cal.getTimeInMillis();

        // 活动结算时间
        String[] balanceTimeStr =
                StringUtils.split(
                        DiscreteDataCfgCache.me().getStringData(DiscreteDataID.ENDLESS_CLOISTER,
                                DiscreteDataKey.BALANCE_TIME), ":");
        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(balanceTimeStr[0]));
        cal.set(Calendar.MINUTE, Integer.parseInt(balanceTimeStr[1]));
        balanceTime = cal.getTimeInMillis();

        // 发放奖励及重置时间
        String[] resetTimeStr =
                StringUtils.split(
                        DiscreteDataCfgCache.me().getStringData(DiscreteDataID.ENDLESS_CLOISTER,
                                DiscreteDataKey.RESETTING_TIME), ":");
        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(resetTimeStr[0]));
        cal.set(Calendar.MINUTE, Integer.parseInt(resetTimeStr[1]));
        resetTime = cal.getTimeInMillis();
    }

    /**
     * 检查活动进行阶段变化
     */
    public void checkStepUpdate(Date date) {
        long t = date.getTime();
        // 有考虑到服务器重启，跳过某些阶段，所以依次检测更改阶段状态
        int oldStep = step;
        if (step == EndlessCloisterConstant.STEP_READY) {// 准备阶段
            if (t >= openTime) {
                step = EndlessCloisterConstant.STEP_OPEN;
            }
        }
        if (step == EndlessCloisterConstant.STEP_OPEN) {// 开启阶段
            if (t >= balanceTime) {
                step = EndlessCloisterConstant.STEP_BALANCE;
                log.debug("----无尽回廊进入结算阶段---");
            }
        }
        if (step == EndlessCloisterConstant.STEP_BALANCE) {// 结算阶段
            if (t >= resetTime) {
                log.debug("----无尽回廊发奖及重置---");
                // 发放奖励(假设重启服务器后重复调用也没关系，玩家如果今日已经发过奖励，将不再发放)
                Collection<Player> players = OnlinePlayerCache.getAll();
                for (Player player : players) {
                    checkReward(player);
                }
                step = EndlessCloisterConstant.STEP_OVER;
            }
        }
        if (!DateUtils.isSameDay(this.date, date)) {
            log.debug("--无尽回廊  跨天--");
            // 跨天,重新解析活动时间
            parseTimes();
            this.date = date;
            step = EndlessCloisterConstant.STEP_READY;
        }
        // 通知客户端更新活动阶段信息
        if (oldStep != step) {
            updateStepToClients();
        }
    }

    /**
     * 登录刷新检查
     */
    public void loginRefresh(Player player) {
        checkReward(player);
    }

    /**
     * 检查发放奖励
     */
    public void checkReward(Player player) {
        PlayerDataProxy pdProxy = player.getPlayerDatasFkPlayerId().getPlayerDataProxy();
        EndlessVO endlessVO = pdProxy.getEndlessVO();
        // 跳过没有挑战的
        int todayBest = endlessVO.getTodayBest();
        if (todayBest == 0) {
            return;
        }
        // 跳过今日已领奖的
        if (DateUtils.isSameDay(new Date(endlessVO.getLastRewardTime()), new Date())) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        // 今日已经过了领奖时间或者上次通关时间不是今日，则补发奖励
        if (nowTime > resetTime
                || !DateUtils.isSameDay(new Date(endlessVO.getLastPassTime()), new Date())) {
            endlessVO.setLastRewardTime(nowTime);
            // 邮件发奖
            EndlessCloisterLevelCfg cfg = EndlessCloisterLevelCfgCache.me().getById(todayBest);
            if (cfg != null) {
                LogDsp logDsp =
                        LogDsp.newBuilder(GoodsDsp.ENDLESS_CLOISTER_BALANCE).addAttr("todayBest",
                                todayBest);
                Map<String, String> map = new HashMap<String, String>();
                map.put("a", String.valueOf(cfg.getOrder()));
                MailManager.me().sendPersonalMail(0, player.getId(), MailConstant.TEXT_TYPE_CONFIG,
                        "mail.endless.title", "mail.endless.content", map, cfg.getFloorReward(),
                        logDsp);
            }
            // 重置
            endlessVO.setTodayBest(0);
            endlessVO.setTodayCostTime(0);
            endlessVO.setNowStage(0);
            pdProxy.save();
        }
    }

    /** 获取初始挑战层级关卡id */
    public int getInitStageId() {
        int week = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1;
        List<Integer> list = weekLevelMap.get(week == 0 ? 7 : week);
        return list.get(0);
    }

    /** 获取跳过层级 */
    public int getNextStageId(int nowStageId, int costTime) {
        int nextStageId = nowStageId + 1;// 默认逐级挑战
        int skipLev = getSkipLevel(costTime);
        if (skipLev > 0) {
            // 计算中间有无boss关卡，有boss关卡先跳到boss关卡
            int k = 0;
            EndlessCloisterLevelCfg cfg = null;
            for (int i = 0; i < skipLev; i++) {
                cfg = EndlessCloisterLevelCfgCache.me().getById(nextStageId + i);
                if (cfg == null || cfg.getDifficulty() == 2) {
                    break;
                }
                k++;
            }
            nextStageId += k;
        }
        int week = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1;
        List<Integer> list = weekLevelMap.get(week == 0 ? 7 : week);
        if (list.indexOf(nextStageId) < 0) {
            nextStageId = -1;// 到达满级（配置表里找不到了）
        }
        return nextStageId;
    }

    /** 获取跳过层级 */
    public int getSkipLevel(int costTime) {
        for (SkipLevelsObj obj : skipList) {
            if (costTime >= obj.getMinTime() && costTime <= obj.getMaxTime()) {
                return obj.getSkipLev();
            }
        }
        return 0;
    }

    /** 通知客户端更新活动阶段信息 */
    public void updateStepToClients() {
        Collection<Player> players = OnlinePlayerCache.getAll();
        for (Player player : players) {
            RspEndlessCloisterInfo info =
                    EndlessCloisterMsgBuilder.createEndlessCloisterInfo(player);
            player.getPlayerProxy().sendMsg(
                    MessageManager.me().create(EndlessCloisterBO.getInfo, ProtoUnit.toByte(info)));
        }
    }

    /** 跳级封装对象 */
    private class SkipLevelsObj {
        /** 最小时间 */
        int minTime;
        /** 最大时间 */
        int maxTime;
        /** 跳过层级 */
        int skipLev;

        public SkipLevelsObj(int minTime, int maxTime, int skipLev) {
            this.minTime = minTime;
            this.maxTime = maxTime;
            this.skipLev = skipLev;
        }

        public int getMinTime() {
            return minTime;
        }

        public int getMaxTime() {
            return maxTime;
        }

        public int getSkipLev() {
            return skipLev;
        }
    }
}
